package com.redstar.HappyRefresh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.redstar.HappyRefresh.audit.ImageAuditService;
import com.redstar.HappyRefresh.audit.TextAuditService;
import com.redstar.HappyRefresh.cache.UserInfo;
import com.redstar.HappyRefresh.constant.AuditStatus;
import com.redstar.HappyRefresh.mapper.UserMapper;
import com.redstar.HappyRefresh.pojo.*;
import com.redstar.HappyRefresh.response.AuditResponse;
import com.redstar.HappyRefresh.service.*;
import com.redstar.HappyRefresh.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private FavoritesService favoritesService;
    @Autowired
    private FollowService followService;
    @Autowired
    private TypeService typeService;
    @Autowired
    private UserSubscribeService userSubscribeService;
    @Autowired
    private InterestPushService interestPushService;
    @Autowired
    private TextAuditService textAuditService;
    @Autowired
    private ImageAuditService imageAuditService;
    @Autowired
    private FileService fileService;

    @Override
    public UserVO getInfo(Long userId) { // 查询用户信息
        User user = getById(userId);
        UserVO userVO = new UserVO();
        if (ObjectUtils.isEmpty(userVO)) { // 无法查询到用户信息，直接返回空对象即可
            return userVO;
        }
        // 隐藏敏感信息
        BeanUtils.copyProperties(user, userVO); // 将user中的属性相同的数据复制到userVo中
        // 查询用户关注数量
        long followCount = followService.getFollowCount(userId);
        userVO.setFollow(followCount);
        // 查询用户粉丝数量
        long fansCount = followService.getFansCount(userId);
        userVO.setFans(fansCount);
        return userVO;
    }

    @Override
    public Page<User> getFollows(BasePage basePage, Long userId) { // 查询指定用户的关注列表，分页数据
        Page<User> page = new Page<>();
        List<Long> followList = followService.getFollowList(basePage, userId); // 用户的关注列表
        if (ObjectUtils.isEmpty(followList)) {
            // 用户关注的列表为null，直接返回
            return page;
        }
        List<Long> fansList = followService.getFansList(null, userId); // 用户的粉丝列表
        Set<Long> fansSet = new HashSet<>(fansList);
        // 得到被当前用户关注的用户详细信息
        Map<Long, User> userMap = getBaseInfoUserToMap(followList);
        List<User> userInfo = new ArrayList<>();
        for (Long id : followList) {
            User user = userMap.get(id);
            user.setEach(fansSet.contains(id));
            userInfo.add(user);
        }
        page.setRecords(userInfo);
        page.setTotal(userInfo.size());
        return page;
    }

    @Override
    public Page<User> getFans(BasePage basePage, Long userId) { // 查询指定用户的粉丝列表，分页数据
        Page<User> page = new Page<>();
        List<Long> fansList = followService.getFansList(basePage, userId); // 用户的粉丝列表
        if (ObjectUtils.isEmpty(fansList)) {
            return page;
        }
        List<Long> followList = followService.getFollowList(null, userId); // 用户的关注列表
        Set<Long> followSet = new HashSet<>(followList);
        Map<Long, User> userMap = getBaseInfoUserToMap(fansList);
        List<User> userInfo = new ArrayList<>();
        for (Long id : fansList) {
            User user = userMap.get(id);
            user.setEach(followSet.contains(id));
            userInfo.add(user);
        }
        page.setRecords(userInfo);
        page.setTotal(userInfo.size());
        return page;
    }

    private Map<Long, User> getBaseInfoUserToMap(List<Long> idList) { // 根据id集合得到用户的详细信息集合，返回值为Map，key为id，value为User
        List<User> userList = new ArrayList<>();
        if (!ObjectUtils.isEmpty(idList)) {
            userList = this.list(new LambdaQueryWrapper<User>().in(User::getId, idList)
                    .select(User::getId, User::getNickName, User::getDescription, User::getSex, User::getAvatar)); // avatar是头像
        }
        // Function.identity()等价于User
        return userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    }

    @Override
    public String saveOrUpdateFavorites(Favorites favorites) { // 添加或修改收藏夹
        Long userId = UserInfo.get();
        Long favoritesId = favorites.getId();
        favorites.setUserId(userId);
        long count = favoritesService.count(new LambdaQueryWrapper<Favorites>()
                .eq(Favorites::getName, favorites.getName()).eq(Favorites::getUserId, favorites.getUserId())
                .ne(Favorites::getId, favorites.getId()));
        if (count == 1) {
            return "false"; // 收藏夹存在且未修改
        }
        favoritesService.saveOrUpdate(favorites);
        return favoritesId == null ? "添加成功" : "修改成功";
    }

    @Override
    public String subscribe(String types) { // 订阅分类，用于兴趣推送
        HashSet<Long> typeSet = new HashSet<>(); // types是以逗号分隔的分类id
        String[] typeNum = types.split(",");
        for (String value : typeNum) {
            typeSet.add(Long.valueOf(value));
        }
        // 根据分类id查询分类信息
        List<Type> typeList = typeService.listByIds(typeSet);
        if (typeList.size() != typeSet.size()) {
            return "你小子传递的分类id中存在无效的部分！";
        }
        // 将分类信息封装为UserSubscribe对象
        ArrayList<UserSubscribe> userSubscribeList = new ArrayList<>();
        Long userId = UserInfo.get();
        for (Long typeId : typeSet) {
            UserSubscribe userSubscribe = new UserSubscribe();
            userSubscribe.setUserId(userId);
            userSubscribe.setTypeId(typeId);
            userSubscribeList.add(userSubscribe);
        }
        // 每次订阅分类后都需要修改兴趣推送的概率，所以需要将当前用户之前订阅的分类删除
        userSubscribeService.remove(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId));
        // 用户订阅分类，批量插入
        userSubscribeService.saveBatch(userSubscribeList);
        // 封装用户分类标签，初始化用户模型
        ArrayList<String> typeLabels = new ArrayList<>();
        for (Type t : typeList) { // 每个分类都有多个标签
            typeLabels.addAll(t.buildLabel());
        }
        interestPushService.initUserModel(userId, typeLabels); // 初始化用户兴趣推送模型
        return "success";
    }

    @Override
    public List<Type> listSubscribeType(Long userId) { // 查询用户订阅的分类,根据用户id查询分类id，再根据分类id查询具体的分类信息
        List<UserSubscribe> userSubscribes = userSubscribeService.list(new LambdaQueryWrapper<UserSubscribe>().eq(UserSubscribe::getUserId, userId));
        if (ObjectUtils.isEmpty(userSubscribes)) {
            return new ArrayList<>();
        }
        List<Long> typeIds = userSubscribes.stream().map(UserSubscribe::getTypeId).collect(Collectors.toList());
        // 返回分类id，分类名称，分类图标
        List<Type> typeList = typeService.list(new LambdaQueryWrapper<Type>().in(Type::getId, typeIds).select(Type::getId, Type::getName, Type::getIcon));
        if (ObjectUtils.isEmpty(typeList) || typeIds.size() != typeList.size()) {
            throw new RuntimeException("listSubscribeType方法出错：查询出的分类id无法找到对应的分类信息，数据库中怎么还有错误数据！！");
        }
        return typeList;
    }

    @Override
    public List<Type> listNoSubscribeType(Long userId) { // 获取用户未订阅的分类
        List<Type> typeList = this.listSubscribeType(userId); // 用户订阅的分类
        List<Type> typeListAll = typeService.list(); // 所有的分类
        if (ObjectUtils.isEmpty(typeList)) { // 用户未订阅分类
            return typeListAll;
        }
        Set<Long> typeIds = typeList.stream().map(Type::getId).collect(Collectors.toSet());
        List<Type> typeListNo = new ArrayList<>();
        for (Type type : typeListAll) {
            if (!typeIds.contains(type.getId())) {
                typeListNo.add(type);
            }
        }
        return typeListNo;
    }

    @Override
    public String followUser(Long followsUserId) { // 关注或取关
        Long userId = UserInfo.get();
        if (Objects.equals(userId, followsUserId)) {
            return "false"; // 自己不能关注自己
        }
        // 关注和取关都需要修改关注列表和粉丝列表，取关还需要删除当前用户收件箱中的视频
        return followService.followUser(userId, followsUserId);
    }

    @Override
    public void updateUserModel(Model model) { // 修改用户模型
        Long userId = UserInfo.get();
        UserModel userModel = new UserModel();
        userModel.setUserId(userId);
        userModel.setModels(Collections.singletonList(model));
        interestPushService.updateUserModel(userModel);
    }

    @Override
    public String updateUser(UpdateUserVO user) { // 修改用户信息
        Long userId = UserInfo.get();
        User oldUser = this.getById(userId);
        // 对修改的信息进行审核
        String nickName = user.getNickName();
        if (!Objects.equals(nickName, oldUser.getNickName())) { // 昵称，在参数传递时已校验，昵称不能为null
            AuditResponse audit = textAuditService.audit(nickName);
            if (!Objects.equals(audit.getAuditStatus(), AuditStatus.SUCCESS)) {
                return "昵称存在违规信息";
            }
        }
        Long avatar = user.getAvatar();
        if (!ObjectUtils.isEmpty(avatar) && !Objects.equals(avatar, oldUser.getAvatar())) { // 头像
            AuditResponse audit = imageAuditService.audit(fileService.getById(avatar).getFileKey());
            if (!Objects.equals(audit.getAuditStatus(), AuditStatus.SUCCESS)) {
                return "头像存在违规信息";
            }
        }
        String description = user.getDescription();
        if (!ObjectUtils.isEmpty(description) && Objects.equals(description, oldUser.getDescription())) { // 描述信息
            AuditResponse audit = textAuditService.audit(description);
            if (!Objects.equals(audit.getAuditStatus(), AuditStatus.SUCCESS)) {
                return "描述信息存在违规信息";
            }
        }
        Long defaultFavoritesId = user.getDefaultFavoritesId();
        if (!ObjectUtils.isEmpty(defaultFavoritesId)) {
            // 校验defaultFavoritesId是否存在
            long count = favoritesService.count(new LambdaQueryWrapper<Favorites>().eq(Favorites::getId, defaultFavoritesId));
            if (count < 1) {
                return "新的默认收藏夹不存在";
            }
        }
        Boolean sex = user.getSex();
        if (!ObjectUtils.isEmpty(sex)) {
            oldUser.setSex(sex);
        }
        this.updateById(oldUser);
        return "success";
    }

    @Override
    public String register(RegisterVO registerVO) { // 用户注册
        String email = registerVO.getEmail();
        // 先判断邮箱是否已被注册
        long count = count(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
        if (count != 0) {
            return "邮箱已被注册";
        }
        AuditResponse audit = textAuditService.audit(registerVO.getNickName());
        if (!Objects.equals(audit.getAuditStatus(), AuditStatus.SUCCESS)) {
            return "用户昵称存在违规信息";
        }
        // 填充用户信息
        User user = new User();
        user.setNickName(registerVO.getNickName());
        user.setEmail(registerVO.getEmail());
        user.setDescription("这个人很懒，什么都没留下...");
        user.setPassword(registerVO.getPassword());
        // 需要先将用户信息写入数据库，默认收藏夹绑定用户需要用户id
        save(user);
        // 创建默认收藏夹
        Favorites favorites = new Favorites();
        favorites.setUserId(user.getId());
        favorites.setName("默认收藏夹");
        // 将默认收藏集信息写入数据库
        favoritesService.save(favorites);
        // 用户绑定默认收藏夹
        user.setDefaultFavoritesId(favorites.getId());
        updateById(user);
        return "success";
    }

    @Override
    public String findPassword(FindPWVO findPWVO) { // 找回密码
        long count = count(new LambdaQueryWrapper<User>().eq(User::getEmail, findPWVO.getEmail()));
        if (count == 0) {
            return "账号信息不存在，请先注册";
        }
        // 填充用户信息
        User user = new User();
        user.setEmail(findPWVO.getEmail());
        user.setPassword(findPWVO.getNewPassword());
        // 修改密码
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getPassword, findPWVO.getNewPassword()).eq(User::getEmail, findPWVO.getEmail());
        update(user, updateWrapper);
        return "success";
    }

    @Override
    public HashMap<String, Object> login(User user) { // 用户登录
        String password = user.getPassword();
        String email = user.getEmail();
        user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail,email));
        if (ObjectUtils.isEmpty(user)) {
            throw new RuntimeException("login方法：账号不存在，请先进行注册");
        }
        if (!password.equals(user.getPassword())) {
            throw new RuntimeException("login方法：账号或密码错误");
        }
        String token = JwtUtils.getToken(user.getId(), user.getNickName());
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("nickname", user.getNickName());
        map.put("user", user);
        return map;
    }
}
